import React = require("react");
import { PageDesigner, EditorPanel, ComponentDefine, ComponentData, PropertyEditorInfo, Component } from "maishu-jueying";
import "jquery-ui"
import { ComponentPanel } from "../component-panel";
import { Application, Page, PageContext } from "maishu-chitu-react";
import { ComponentInfo } from "components/common/component";
import { buttonOnClick } from "maishu-ui-toolkit";
import { LocalService } from "services/local-service";
import { ValueStore } from "maishu-chitu";
import { loadLess, stationPath } from "common";
import { addComponentDataToFooter, removeChildComponentData as removeComponentData, removeComponentDataFromFooter, pageDatas, defaultPageDatas } from "services/page-datas";
import { Menu } from "components/menu/component";
import { componentRenders } from "component-renders/index";
import { ShoppingCartBar } from "components/single-colunm-products/shopping-cart-bar";
import { PageDataRecord } from "entities";
import * as ui from "maishu-ui-toolkit";
import { contextName } from "json!websiteConfig";
import site from "site";
import ReactDOM = require("react-dom");
import { errorHandle } from "maishu-chitu-admin/static";
import { ComponentLoader } from "./component-loader";

requirejs({ context: contextName }, ["css!devices"]);

type PartialPageDataRecord = { [P in "id" | "pageData" | "name" | "type"]: PageDataRecord[P] };
interface Props {
    app: Application,
    pageDataRecord: PartialPageDataRecord,
    hideToolbar?: boolean,
    hideEditorPanel?: boolean,
    hidePageSettingPanel?: boolean,
}

interface State {
    pageData: ComponentData,
}

export class MyPageDesigner extends PageDesigner {
    componentPanel = new ValueStore<ComponentPanel>();
}

export let DesignPageContext = React.createContext<{ designPage?: DesignView }>({});

const componentLoaded = "componentLoaded";
export class DesignView extends React.Component<Props, State> {
    private editorPanel: EditorPanel;
    private componentPanel: ComponentPanel;
    private localService: LocalService;
    private _designer: MyPageDesigner;

    private static initComponents = false;

    designer: ValueStore<MyPageDesigner> = new ValueStore();
    private designerElement: HTMLElement;

    constructor(props: Props) {
        super(props);

        this.state = {
            pageData: this.props.pageDataRecord.pageData,
        };
        this.localService = this.props.app.createService(LocalService);
        if (!DesignView.initComponents) {
            DesignView.initComponents = true;
            loadEditors(this.localService);
            loadLessFiles(this.localService);
        }

        this.designer.attach(designer => {
            if (!designer) return;
            //==================================================================================
            // 重写 designer 添加组件方法，在添加组件之前，先加载组件
            let appendComponent = designer.appendComponent;
            designer.appendComponent = async (parentId: string, componentData: ComponentData, componentIndex?: number) => {
                await ComponentLoader.loadSingleComponent(componentData);
                appendComponent.apply(designer, [parentId, componentData, componentIndex]);
            }
            //==================================================================================
        })
    }

    private customRender(editComponents: ComponentData[], items: PropertyEditorInfo[]) {
        console.assert(editComponents.length == 1);
        let typename = editComponents[0].type;
        let componentCustomRender = componentRenders[typename];
        if (!componentCustomRender)
            return null;

        return componentCustomRender(items);
    }
    async save(): Promise<any> {
        let { pageData } = this.state;
        let value = pageData[componentLoaded];
        delete pageData[componentLoaded];
        await this.localService.savePageDataRecord(this.props.pageDataRecord);
        pageData[componentLoaded] = value;
    }

    async setMenu(value: boolean) {
        let pageData = this._designer.pageData;
        if (value) {
            let menuComponentData: ComponentData = { type: Menu.name };
            addComponentDataToFooter(pageData, menuComponentData);
        }
        else {
            removeComponentDataFromFooter(pageData, Menu.name);
        }
        this.setState({ pageData });
    }

    async setSettleBar(value: boolean) {
        let pageData = this._designer.pageData;
        if (value) {
            let componentData: ComponentData = { type: ShoppingCartBar.name };
            addComponentDataToFooter(pageData, componentData);
        }
        else {
            removeComponentDataFromFooter(pageData, ShoppingCartBar.name);
        }
        this.setState({ pageData });
    }

    hasMenu(pageData: ComponentData) {
        let r = pageData.children.filter(o => o.type == Menu.name).length > 0;
        return r;
    }

    hasSettleBar(pageData: ComponentData) {
        let r = pageData.children.filter(o => o.type == ShoppingCartBar.name).length > 0;
        return r;
    }

    preivew() {
        let { pageDataRecord } = this.props;
        let pageData: ComponentData = pageDataRecord.pageData;
        console.assert(pageData != null);

        let hasChanged = false;
        if (hasChanged || !pageData.props.id) {
            ui.alert({ title: '提示', message: `预览前必须先保存页面, 请点击"保存"按钮保存页面` });
            return;
        }

        let mobilePath = stationPath("mobile");
        let url = `${mobilePath}?appKey=${this.localService.applicationId}#page?id=${pageDataRecord.id}`;
        open(url, '_blank');
    }

    // componentWillReceiveProps
    static getDerivedStateFromProps(props: Props): Partial<State> {
        if (props.pageDataRecord == null) {
            return { pageData: defaultPageDatas.empty() };
        }
        return { pageData: props.pageDataRecord.pageData };
    }

    async componentPanelRef(e: ComponentPanel) {
        if (!e || this.componentPanel) return;
        this.componentPanel = e;

        //==========================================================================================
        // 设置组件工具栏
        let componentInfos: ComponentInfo[] = await this.localService.componentInfos(); //getComponentInfos(this.props.app);
        console.assert(componentInfos != null);

        componentInfos = componentInfos.filter(o => o.displayName != null);
        let components = componentInfos.map(o => ({
            componentData: {
                type: o.name,
                props: {
                    attr: { movable: false, container: false, showHandler: false, resize: false }
                },
            },
            displayName: o.displayName,
            icon: o.icon,
            introduce: o.introduce
        }) as ComponentDefine)
        this.componentPanel.setComponets(components);
        //==========================================================================================
        console.assert(this._designer != null)
        this.componentPanel.designer = this._designer;
        this._designer.componentPanel.value = this.componentPanel;
    }

    editorPanelRef(e: EditorPanel) {
        if (!e || this.editorPanel)
            return;

        this.editorPanel = e;
        this.editorPanel.designer = this._designer;
    }

    render() {
        let { pageData } = this.state;
        if (!pageData[componentLoaded]) {
            ComponentLoader.loadPageCompontents(pageData)
                .then(() => {
                    pageData[componentLoaded] = true;
                    this.setState({ pageData });
                })
                .catch(err => {
                    console.error(err);
                })
            return site.loadingElement;
        }

        let { hidePageSettingPanel } = this.props;
        return <DesignPageContext.Provider value={{ designPage: this }}>
            <React.Fragment>
                <div className="marvel-device iphone8 black pull-left">
                    <div className="top-bar"></div>
                    <div className="sleep"></div>
                    <div className="volume"></div>
                    <div className="camera"></div>
                    <div className="sensor"></div>
                    <div className="speaker"></div>
                    <article className="screen mobile-page"
                        ref={e => {
                            if (!e) return;
                            if (!this.designerElement) {
                                // this.designerElement = document.createElement("div");
                                // e.appendChild(this.designerElement);
                                this.designerElement = e;
                            }
                            let page = { element: e as HTMLElement, app: this.props.app } as Page;
                            ReactDOM.render(<PageContext.Provider value={{ page }}>
                                <MyPageDesigner pageData={pageData}
                                    ref={e => {
                                        if (e == null || this._designer != null) return;

                                        this._designer = this._designer || e;
                                        this.designer.value = this._designer;
                                    }} />
                            </PageContext.Provider>, this.designerElement)
                        }}>
                    </article>
                    <div className="home"></div>
                    <div className="bottom-bar"></div>
                </div>
                <div style={{ marginLeft: 440 }}>
                    <ul style={{ height: 32, margin: 0, padding: 0 }}>
                        <li className="pull-right">
                            <button className="btn btn-sm btn-primary">
                                <i className="icon-copy"></i><span>更换模板</span>
                            </button>
                            <div className="btn-group">
                                <button className="btn btn-sm btn-primary dropdown-toggle">
                                    <i className="icon-camera"></i>
                                    <span>存为快照</span>
                                </button>
                                <button type="button" className="btn btn-sm btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
                                    <i className="icon-caret-down"></i>
                                </button>
                                <ul className="dropdown-menu">
                                    <li style={{ padding: "6px 0px" }}>
                                        <a className="btn-link">查看快照<span className="badge pull-right">2</span></a>
                                    </li>
                                </ul>
                            </div>
                            <button className="btn btn-sm btn-primary" onClick={() => this.preivew()}>
                                <i className="icon-eye-open"></i><span>预览</span>
                            </button>
                            <button className="btn btn-sm btn-primary"
                                ref={e => {
                                    if (!e) return;
                                    buttonOnClick(e, () => this.save(), { toast: "保存成功!" })
                                }}>
                                <i className="icon-save"></i>
                                <span>保存</span></button>
                            <button className="btn btn-sm btn-primary"
                                onClick={() => this.props.app.back()}>
                                <i className="icon-reply"></i><span>返回</span>
                            </button>
                        </li>
                        <li className=""></li>
                    </ul>
                    <hr style={{ margin: 0, marginTop: -2 }} />
                    <div>
                        {hidePageSettingPanel ? null : <div className="pull-right" style={{ width: 240 }}>
                            <div className="panel panel-default">
                                <div className="panel-heading">页面设置</div>
                                <ul className="list-group">
                                    <li className="list-group-item">
                                        <div className="pull-left" style={{ width: "calc(100% - 60px)" }}>
                                            显示导航菜单</div>
                                        <label className="switch">
                                            <input type="checkbox" className="ace ace-switch ace-switch-5"
                                                checked={this.hasMenu(pageData)}
                                                onChange={e => this.setMenu(e.target.checked)} />
                                            <span className="lbl middle"></span>
                                        </label>
                                    </li>
                                    <li className="list-group-item">
                                        <div className="pull-left" style={{ width: "calc(100% - 60px)" }}>
                                            显示购物车结算栏</div>
                                        <label className="switch">
                                            <input type="checkbox" className="ace ace-switch ace-switch-5"
                                                checked={this.hasSettleBar(pageData)}
                                                onChange={e => this.setSettleBar(e.target.checked)} />
                                            <span className="lbl middle"></span>
                                        </label>
                                    </li>
                                </ul>
                            </div>
                        </div>}
                        <div style={{ marginRight: hidePageSettingPanel ? null : 260 }}>
                            {this.props.hideToolbar ? null : <>
                                <h5 style={{ display: "block" }}>页面组件</h5>
                                <ComponentPanel ref={this.componentPanelRef.bind(this)} />
                            </>}
                            {this.props.hideEditorPanel ? null :
                                <EditorPanel ref={this.editorPanelRef.bind(this)} className="well"
                                    customRender={(a, b) => this.customRender(a, b)} />}
                            {this.props.children}
                        </div>
                    </div>
                </div>
            </React.Fragment >
        </DesignPageContext.Provider>
    }
}


async function loadEditors(localService: LocalService) {
    let files = await localService.clientFiles();
    let editorFiles = files.filter(o => o.startsWith("components") && o.endsWith(".js") && o.indexOf("editor") >= 0)
        .map(o => o.substring(0, o.length - ".js".length));

    editorFiles.forEach(path => requirejs({ context: contextName }, [path]));
}

async function loadLessFiles(localService: LocalService) {
    let files = await localService.clientFiles();
    let editorLessFiles = files.filter(o => o.startsWith("components") && o.endsWith("editor.less"));
    editorLessFiles.forEach(path => {
        loadLess(path);
    })
}